/*******************************************************************************
 * Copyright (c) 2001, 2002 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.core.internal.api;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.sourceforge.perforce.api.IError;
import net.sourceforge.perforce.api.IPerforceCommand;
import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.api.ISubmitResult;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;

/**
  * ClientUser object for the 'p4 submit' command.
  * 
  * @version $Revision: 252 $
  * @author  <a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
public class Submit extends AbstractPerforceCommand implements IPerforceCommand
{
	// --------------------------------------------------------------------------- Private Variables

	/** Stores the changespec. */	
	private ChangeSpec changeSpec;
	/** Stores the result of the command. */
	private List resultList = new ArrayList();

	// --------------------------------------------------------------- Public Static Factory Methods

	/** Convenience method for creating instances of Change.
	  * 
	  * @param changeSpec the change specification used for submitting.
	  * @param monitor the monitor for progress feedback.
	  * @return the new Submit instance.
	  */
	public static final Submit newInstanceForOutput(ChangeSpec changeSpec, IProgressMonitor monitor)
	{
		MultiStatus status = new MultiStatus(PerforceCorePlugin.ID, IStatus.OK, "", null);
		return new Submit(status, changeSpec, monitor);
	}
	
	// ------------------------------------------------------------------------ Private Constructors
	
	/** Constructor for Submit.
	  * 
	  * @param status the MultiStatus object.
	  * @param changeSpec the changelist specification.
  	  * @param monitor the monitor for progress feedback.
	  */
	private Submit(MultiStatus status, ChangeSpec changeSpec, IProgressMonitor monitor)
	{
		super(status, monitor);
		this.changeSpec = changeSpec;
		
		getProgressMonitor().beginTask("", changeSpec.getFileCount() * 1000);          //$NON-NLS-1$
	}

	// -------------------------------------------------------- Public Methods (IClientUserDelegate)

	/** @see IClientUserDelegate#inputData() */
	public String inputData(IError error)
	{
		return changeSpec.toString();
	}

	/** @see net.sourceforge.perforce.api.IClientUserDelegate#outputError(java.lang.String) */
	public void outputError(String errorString) 
	{
		IStatus tempStatus = PerforceStatus.decode(errorString, IStatus.OK);		
		IStatus[] children = getMultiStatus().getChildren();
		
		MultiStatus multiStatus = 
			new MultiStatus(
				PerforceCorePlugin.ID,
				IStatus.ERROR,
				children,
				tempStatus.getMessage(),
				null);
		setMultiStatus(multiStatus);				
	}

	/** @see IClientUserDelegate#outputInfo(char, String) */
	public void outputInfo(char level, String infoString)
	{
		IStatus tempStatus = PerforceStatus.decode(infoString, IStatus.OK);
							
		if (level == '0')
		{
			int start = infoString.indexOf("//");                                      //$NON-NLS-1$
			int stop = infoString.lastIndexOf('#');
			
			if (tempStatus.getCode() == PerforceStatus.REFRESHING.getCode())
			{
				String file = infoString.substring(0, infoString.lastIndexOf('#'));
				
				for (Iterator it = resultList.iterator(); it.hasNext();)
				{
					Result result = (Result) it.next();
					if (result.getDepotFilename().equals(file))
					{
						result.setRefreshed(true);
					}						
				}
			}
			else
			if (tempStatus.getCode() == PerforceStatus.MUST_RESOLVE_BEFORE_SUBMITTING.getCode())
			{
				stop = infoString.indexOf(" - must resolve ");                         //$NON-NLS-1$

				Result result = new Result();
				
				result.setDepotFilename(infoString.substring(start, stop));
				resultList.add(result);
				
				getProgressMonitor().subTask("Processing " + result.getDepotFilename());
				getProgressMonitor().worked(1000);
			}
			else
			if (tempStatus.getCode() == PerforceStatus.MUST_RESOLVE.getCode())
			{
			}
			else
			if (start != -1 && stop != -1 && start < stop)
			{
				Result result = new Result();
				
				result.setDepotFilename(infoString.substring(start, stop));
				result.setAction(infoString.substring(0, start - 1));
				
				resultList.add(result);
				
				getProgressMonitor().subTask("Processing " + result.getDepotFilename());
				getProgressMonitor().worked(1000);
			}
			else
			{
				getProgressMonitor().subTask(infoString);
			}			
		}
			
		getMultiStatus().merge(tempStatus);
	}
	
	/** @see net.sourceforge.perforce.api.IClientUserDelegate#finished() */
	public void finished() 
	{
		getProgressMonitor().done();
	}


	// ----------------------------------------------------------- Public Methods (IPerforceCommand)

	/** @see IPerforceCommand#getCommand() */
	public String getCommand()
	{
		return "submit";                                                               //$NON-NLS-1$
	}
	
	/** @see IPerforceCommand#getStatus() */
	public IStatus getStatus()
	{
		return getMultiStatus();
	}
	
	// ------------------------------------------------------------------------------ Public Methods
	
	/** Returns an array of result objects.
	  * 
	  * @return affected files. 
	  */
	public ISubmitResult[] getResult()
	{
		return (ISubmitResult[]) resultList.toArray(new ISubmitResult[resultList.size()]);
	}
	
	// ----------------------------------------------------------------------- Public Nested Classes
	
	/** Represents the result of the submit action. */
	public static class Result implements ISubmitResult 
	{
		// ----------------------------------------------------------------------- Private Variables
		
		/** Stores the depot filename of the resource. */
		private String depotFilename;
		/** Stores the performed action. */
		private String action; 
		/** Stores whether the item was refreshed or not. */
		private boolean refreshed;
		
		// -------------------------------------------------------------------------- Public Methods
				
		/** @see ISubmitResult#getDepotFilename() */
		public String getDepotFilename()
		{
			return depotFilename;
		}
		
		/** @see ISubmitResult#getAction() */
		public String getAction()
		{
			return action;
		}
		
		/** @see ISubmitResult#isRefreshed() */
		public boolean isRefreshed()		
		{
			return refreshed;
		}
		
		/** @see java.lang.Object#toString() */
		public String toString() 
		{
			String result = action + " " + depotFilename;
			if (refreshed)
			{
				result += " [refreshed]";
			}
			
			return result;
		}
		
		// ------------------------------------------------------------------------- Private Methods
		
		/** Sets the depot filename.
		  *
		  * @param depotFilename the new depot filename. 
		  */
		private void setDepotFilename(String depotFilename)
		{
			this.depotFilename = depotFilename;
		}
		
		/** Sets the action.
		  *
		  * @param action the new action. 
		  */
		private void setAction(String action)
		{
			this.action = action;
		}

		/** Sets the value of the refreshed flag.
		  *
		  * @param refreshed the new value. 
		  */		
		private void setRefreshed(boolean refreshed)
		{
			this.refreshed = refreshed;
		}
	}
}
